package com.cheng.im.gateway.session.manager;

import com.cheng.im.common.entity.ImNode;
import com.cheng.im.gateway.entity.ImWorker;
import com.cheng.im.gateway.session.LocalSession;
import com.cheng.im.gateway.session.RemoteSession;
import com.cheng.im.gateway.session.ServerSession;
import com.cheng.im.gateway.session.dao.SessionCacheDAO;
import com.cheng.im.common.entity.SessionCache;
import com.cheng.im.common.entity.UserCache;
import com.cheng.im.gateway.session.dao.impl.RedissonUserCacheImpl;
import io.netty.channel.ChannelHandlerContext;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Cheng
 */
@Slf4j
@Component
public class SessionManger {

//    @Resource
//    private SessionCacheDAO sessionCacheDAO;
    @Resource
    private RedissonUserCacheImpl userCacheDAO;

    private static SessionManger singleInstance = null;

    public static SessionManger inst()
    {
        return singleInstance;
    }

    public static void setSingleInstance(SessionManger singleInstance)
    {
        SessionManger.singleInstance = singleInstance;
    }

    private ConcurrentHashMap<String, ServerSession> sessionMap = new ConcurrentHashMap();

    public void addLocalSession(LocalSession session) {
        //step1: 保存本地的session 到会话清单
        String sessionId = session.getSessionId();
        sessionMap.put(sessionId, session);


        String uid = session.getUser().getUserId();


        //step2: 缓存session到redis
        ImNode node = ImWorker.getInst().getLocalNode();

        SessionCache sessionCache = new SessionCache(sessionId, uid, node, session.getUser().getPlatform());
//        sessionCacheDAO.save(sessionCache);

        //step3:增加用户的session 信息到用户缓存
        userCacheDAO.addSession(uid, sessionCache, session.getUser().getAppId());

//        //step4: 增加用户数
//        OnlineCounter.getInst().increment();
//        log.info("本地session增加：{},  在线总数:{} ",
//                JsonUtil.pojoToJson(session.getUser()),
//                OnlineCounter.getInst().getCurValue());
//        ImWorker.getInst().incBalance();
//
//        notifyOtherImNodeOnLine(session);
        ImWorker.getInst().incBalance();
    }


    // 关闭连接
    public void closeSession(ChannelHandlerContext ctx)
    {
        LocalSession session = ctx.channel().attr(LocalSession.SESSION_KEY).get();
        if (null == session || !session.isValid())
        {
            log.error("session is null or isValid");
            return;
        }

        session.close();
        //删除本地的会话和远程会话
        this.removeSession(session.getSessionId(), session.getUser().getAppId());
    }

    /**
     * 移除本地session和缓存
     * @param sessionId
     */
    public void removeSession(String sessionId, String appId)
    {
        if (!sessionMap.containsKey(sessionId)) return;

        ServerSession session = sessionMap.get(sessionId);
        String uid = session.getUserId();

        ImWorker.getInst().decrBalance();

        //分布式：分布式保存user和所有session，根据 sessionId 删除用户的会话
        userCacheDAO.removeSession(uid, sessionId, appId);

        //本地：从会话集合中，删除会话
        sessionMap.remove(sessionId);
    }

    public List<ServerSession> getSessionsBy(String userId, String appId)
    {
        //分布式：分布式保存user和所有session，根据 sessionId 删除用户的会话
        UserCache user = userCacheDAO.get(userId, appId);
        if (null == user)
        {
            log.info("用户：{} 下线了? 没有在缓存中找到记录 ", userId);
            return null;
        }
        Map<String, SessionCache> allSession = user.getMap();
        if (null == allSession || allSession.size() == 0)
        {
            log.info("用户：{} 下线了? 没有任何会话 ", userId);
            return null;
        }
        List<ServerSession> sessions = new LinkedList<>();

        allSession.values().stream().forEach(sessionCache ->
        {
            String sid = sessionCache.getSessionId();
            // 在本地，取得session
            ServerSession session = sessionMap.get(sid);
            // 本地session没有命中，创建远程的session，加入会话集合
            if (session == null)
            {
                // 删除远程缓存中存在的缓存  而本地缓存不存在的缓存
                // 也就是本地没有这个连接会话缓存，但是远程缓存中存在这个连接会话缓存，这时候得删除远程缓存中的这个连接会话缓存
                ImNode imNode = sessionCache.getImNode();
                ImNode localNode = ImWorker.getInst().getLocalNode();
                if (imNode.getHost().equals(localNode.getHost()) && imNode.getPort().equals(localNode.getPort())) {
                    userCacheDAO.removeSession(userId, sid, appId);
//                    sessionCacheDAO.remove(sid);

                    return;
                }
                // 连接在其他im节点的情况
                session = new RemoteSession(sessionCache);
                sessionMap.put(sid, session);
            }
            sessions.add(session);
        });
        return sessions;
    }

    /**
     * 排除除了当前会话，获取其他在线端的Session
     */
    public List<ServerSession> getSessionsByExclusiveCurrent(String userId, LocalSession fromSession, String appId) {
        //分布式：分布式保存user和所有session，根据 sessionId 删除用户的会话
        UserCache user = userCacheDAO.get(userId, appId);
        if (null == user)
        {
            log.error("出错了：{} 下线了? 自己还在线都在缓存显示下线了 ", userId);
            return null;
        }
        Map<String, SessionCache> allSession = user.getMap();
        if (null == allSession || allSession.size() == 0)
        {
            log.info("用户：{} 下线了? 没有任何会话 ", userId);
            return null;
        }

        List<ServerSession> sessions = new LinkedList<>();

        allSession.values().stream().forEach(sessionCache ->
        {
            String sid = sessionCache.getSessionId();
            // 排除本地的
            if (fromSession.getSessionId().equals(sid)) {
                return;
            }

            // 在本地，取得session
            ServerSession session = sessionMap.get(sid);
            // 本地session没有命中，创建远程的session，加入会话集合
            if (session == null)
            {
                // 删除远程缓存中存在的缓存  而本地缓存不存在的缓存
                // 也就是本地没有这个连接会话缓存，但是远程缓存中存在这个连接会话缓存，这时候得删除远程缓存中的这个连接会话缓存
                ImNode imNode = sessionCache.getImNode();
                ImNode localNode = ImWorker.getInst().getLocalNode();
                if (imNode.getHost().equals(localNode.getHost()) && imNode.getPort().equals(localNode.getPort())) {
                    userCacheDAO.removeSession(userId, sid, appId);
//                    sessionCacheDAO.remove(sid);

                    return;
                }
                // 连接在其他im节点的情况
                session = new RemoteSession(sessionCache);
                sessionMap.put(sid, session);
            }
            sessions.add(session);
        });
        return sessions;
    }

    public ServerSession getSessionBySession(String sessionId) {
        return sessionMap.get(sessionId);
    }

    public List<LocalSession> getFromLocalSession(String from, LocalSession fromSession, String appId) {
        // 分布式：分布式保存user和所有session，根据 sessionId 删除用户的会话
        UserCache user = userCacheDAO.get(from, appId);
        if (null == user)
        {
            log.error("出错了：{} 下线了? 自己还在线都在缓存显示下线了 ", from);
            return null;
        }

        Map<String, SessionCache> allSession = user.getMap();
        if (null == allSession || allSession.size() == 0)
        {
            log.info("用户：{} 下线了? 没有任何会话 ", from);
            return null;
        }

        List<LocalSession> sessions = new LinkedList<>();

        allSession.values().stream().forEach(sessionCache -> {
            String sid = sessionCache.getSessionId();
            // 排除本地的
            if (fromSession.getSessionId().equals(sid)) {
                return;
            }

            // 在本地，取得session
            LocalSession session = (LocalSession) sessionMap.get(sid);
            // 本地session没有命中，创建远程的session，加入会话集合
            if (session == null)
            {
                return;
            }
            sessions.add(session);
        });

        return sessions;

    }
}
